package com.splic.api.controller.product;

import com.splic.api.service.LoginService;
import com.splic.common.core.DeviceContext;
import com.splic.common.core.domain.ResponseObj;
import com.splic.common.core.redis.RedisCache;
import com.splic.common.exception.BusinessException;
import com.splic.common.utils.StringUtils;
import com.splic.common.utils.security.Md5Utils;
import com.splic.product.domain.Product;
import com.splic.product.domain.User;
import com.splic.product.dto.LoginDto;
import com.splic.product.dto.LoginResultDto;
import com.splic.product.dto.RegisterDto;
import com.splic.product.dto.SendCodeDto;
import com.splic.product.service.*;
import com.splic.product.util.ChinaMobileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/apiLogin")
@Slf4j
public class ApiLoginController {

    @Autowired
    private EmailSendCodeService emailSendCodeServiceImpl;

    @Autowired
    private UserService userServiceImpl;

    @Autowired
    private LoginService loginService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private DeviceService deviceServiceImpl;
    @Autowired
    private ProductService productServiceImpl;
    @Autowired
    private ProductUserService productUserService;

    /**
     * 注册发送邮箱验证码接口
     * @param sendCodeDto
     * @return
     */
    @PostMapping("/sendMobileCode")
    public ResponseObj sendMobileCode(@RequestBody SendCodeDto sendCodeDto){
        try{
            if(StringUtils.isEmpty(sendCodeDto.getAccount())
                    || StringUtils.isEmpty(sendCodeDto.getType())){
                return ResponseObj.ERROR("参数为空");
            }
//            emailSendCodeServiceImpl.sendEmailCode(sendCodeDto)
            return ResponseObj.SUCCESS();
        }catch (BusinessException e){
            log.error("发送验证码失败:{}",e.getMessage());
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("发送验证码失败:{}",e.getMessage());
            return ResponseObj.ERROR("发送验证码失败");
        }
    }
    /**
     * 注册发送邮箱验证码接口
     * @param sendCodeDto
     * @return
     */
    @PostMapping("/sendEmailCode")
    public ResponseObj sendEmailCode(@RequestBody SendCodeDto sendCodeDto){
        try{
            if(StringUtils.isEmpty(sendCodeDto.getAccount())){
                return ResponseObj.ERROR("请输入账号。");
            }
            if(StringUtils.isEmpty(sendCodeDto.getType())){
               return ResponseObj.ERROR("请输入邮件类型。");
            }
            return ResponseObj.SUCCESS(emailSendCodeServiceImpl.sendEmailCode(sendCodeDto));
        }catch (BusinessException e){
            log.error("发送验证码失败:{}产品{}邮箱{}",e.getMessage(), DeviceContext.getProductPackageKey(), sendCodeDto.getAccount());
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("通用发送验证码失败:{}产品{}邮箱{}",e.getMessage(), DeviceContext.getProductPackageKey(), sendCodeDto.getAccount());
            return ResponseObj.ERROR("发送邮件验证码失败");
        }
    }


    /**
     * 用户注册接口
     * @param registerDto
     * @return
     */
    @PostMapping("/register")
    public ResponseObj register(@RequestBody RegisterDto registerDto){
        if (StringUtils.isBlank(registerDto.getAccount())) {
            return ResponseObj.ERROR("请您输入账号。");
        }
        if (StringUtils.isBlank(registerDto.getPassword())) {
            return ResponseObj.ERROR("请您输入密码。");
        }
        if(StringUtils.isEmpty(registerDto.getConfirmPwd())){
            return ResponseObj.ERROR("请您在确认密码一栏输入密码。");
        }
        if(!StringUtils.equals(registerDto.getPassword(),registerDto.getConfirmPwd())){
            return ResponseObj.ERROR("两次输入之密码不一致，请您检查。");
        }
        String regex = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,1000}$";
        if (!registerDto.getPassword().matches(regex)) {
            throw new BusinessException("密码不得少于6位，且需同时包含数字和字母。");
        }
        try {
            Long userId = userServiceImpl.register(registerDto);
            return ResponseObj.SUCCESS(userId);
        }catch (BusinessException e){
            log.error("注册失败:{}",e.getMessage());
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("注册失败:{}",e.getMessage());
            return ResponseObj.ERROR("注册失败");
        }

    }

    /**
     * 登录
     * @param loginDto
     * @return
     */
    @PostMapping("/login")
    public ResponseObj<LoginResultDto> login(@RequestBody LoginDto loginDto){
        log.error("baos:" + loginDto);
        if (StringUtils.isBlank(loginDto.getAccount())) {
            return ResponseObj.ERROR("请您输入账号。");
        }
        if (StringUtils.isBlank(loginDto.getPassword())) {
            return ResponseObj.ERROR("请您输入密码。");
        }
        try {
            User userOld = userServiceImpl.login(loginDto);
            LoginResultDto dto = new LoginResultDto();
            dto.setExistBind(userOld.getExistBind());
            dto.setUserIdentify(userOld.getUserIdentify());
            if (userOld.getExistBind() == 1) {
                return ResponseObj.SUCCESS(dto);
            }
            dto.setToken(loginService.getToken(userOld.getId(),userOld.getPassword()));

            List<String> oldToken = redisCache.getCacheObject(userOld.getUserIdentify() + "oldToken");
            if (oldToken == null) {
                oldToken = new ArrayList<>();
            } else {
                if (oldToken.size() > 20) {
                    oldToken = oldToken.subList(oldToken.size() - 10, oldToken.size() -1);
                }
            }
            oldToken.add(dto.getToken());
            redisCache.setCacheObject(userOld.getUserIdentify() + "oldToken", oldToken);

            LinkedHashMap<String, String> userMap = redisCache.getCacheObject(userOld.getUserIdentify() + "_" + DeviceContext.getProductPackageKey());
            if (userMap == null) {
                userMap = new LinkedHashMap<>();
            }
            userMap.put(DeviceContext.getDeviceIdentify(), dto.getToken());
            redisCache.setCacheObject(userOld.getUserIdentify() + "_" + DeviceContext.getProductPackageKey(), userMap);

            redisCache.setCacheObject(dto.getToken(), DeviceContext.getDeviceIdentify() + "_" + DeviceContext.getProductPackageKey(), 60, TimeUnit.DAYS);
            productUserService.maybeSave(userOld);
            return ResponseObj.SUCCESS(dto);
        }catch (BusinessException e){
            log.error("登录失败:{}产品{}版本{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), loginDto.getAccount());
            if (e.getCode() == 1001) {
                return ResponseObj.ERROR(e.getMessage(), "1001");
            }
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            e.printStackTrace(new PrintStream(baos));
            String exception = baos.toString();
            log.error("baos:" + exception);
            log.error("通用登录失败:{}产品{}版本{}设备{}用户{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), loginDto.getAccount());
            return ResponseObj.ERROR("登录失败");
        }
    }

    /**
     * 中国移动 是否使用移动认证
     * @param
     * @return
     */
    @Deprecated
    @GetMapping("/api/chinaMobilePerm")
    public ResponseObj<String> chinaMobilePerm(){
        try {
            Product product = productServiceImpl.getByPackageKey(DeviceContext.getProductPackageKey());
            if (StringUtils.isEmpty(product.getLoginType())) {
                return ResponseObj.SUCCESS("0");
            }
            return ResponseObj.SUCCESS(product.getLoginType());
        }catch (BusinessException e){
            log.error("是否使用移动认证:{}产品{}版本{}设备{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify());
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("是否使用移动认证:{}产品{}版本{}设备{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify());
            return ResponseObj.ERROR("是否使用移动认证失败");
        }

    }

    /**
     * 中国移动 获取手机号 0存在账户1不存在账户
     * @param
     * @return
     */
    @Deprecated
    @GetMapping("/api/getMobile")
    public ResponseObj<Map<String, String>> getMobile(String token){
        try {
            Product product = productServiceImpl.getByPackageKey(DeviceContext.getProductPackageKey());
            String phoneNumber = ChinaMobileUtils.getMobile(token, product.getCmAppId());
            Map<String, String> map = new HashMap<>();
            if (StringUtils.isNotEmpty(phoneNumber)) {
                User userOld = userServiceImpl.getByAccount(phoneNumber);
                if (userOld != null) {
                    map.put("phoneNumber", phoneNumber);
                    map.put("isAccount", "0");
                } else {
                    map.put("phoneNumber", phoneNumber);
                    map.put("isAccount", "1");
                }
            } else {
                map.put("phoneNumber", "");
                map.put("isAccount", "1");
            }
            return ResponseObj.SUCCESS(map);
        }catch (BusinessException e){
            log.error("获取手机号:{}产品{}版本{}设备{}token{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), token);
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("获取手机号:{}产品{}版本{}设备{}token{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), token);
            return ResponseObj.ERROR("获取手机号");
        }

    }

    /**
     * 中国移动 手机号登录
     * @param
     * @return
     */
    @Deprecated
    @GetMapping("/api/chinaMobileLogin")
    public ResponseObj<LoginResultDto> chinaMobileLogin(String token, Integer isForce){
        try {
            LoginResultDto dto = new LoginResultDto();
            String phoneNumber;
            if (isForce == 0){
                Product product = productServiceImpl.getByPackageKey(DeviceContext.getProductPackageKey());
                phoneNumber = ChinaMobileUtils.getMobile(token, product.getCmAppId());
                if (StringUtils.isEmpty(phoneNumber)) {
                    return ResponseObj.ERROR("获取手机号失败，无法一键登录");
                }
            } else {
                phoneNumber = redisCache.getCacheObject("mobielLogin" + token);
                if (StringUtils.isEmpty(phoneNumber)) {
                    return ResponseObj.ERROR("获取手机号超时，请重试");
                }
            }
            User userOld = userServiceImpl.mobielLogin(token, phoneNumber, isForce);
            if (userOld == null) {
                userOld= new User();
                userOld.setAccount(phoneNumber);
                userOld.setAccountCheck(1);
                userOld.setRegisterTime(new Date());
                userOld.setPassword(Md5Utils.hash("ej123456"));
                userServiceImpl.insert(userOld);
            } else {
                User temp = new User();
                temp.setAccountCheck(1);
                userServiceImpl.update(userOld);
            }

            dto.setToken(loginService.getToken(userOld.getId(),userOld.getPassword()));
            dto.setUserIdentify(userOld.getUserIdentify());

            List<String> oldToken = redisCache.getCacheObject(userOld.getUserIdentify() + "oldToken");
            if (oldToken == null) {
                oldToken = new ArrayList<>();
            } else {
                if (oldToken.size() > 20) {
                    oldToken = oldToken.subList(oldToken.size() - 10, oldToken.size() -1);
                }
            }
            oldToken.add(dto.getToken());
            redisCache.setCacheObject(userOld.getUserIdentify() + "oldToken", oldToken);

            LinkedHashMap<String, String> userMap = redisCache.getCacheObject(userOld.getUserIdentify() + "_" + DeviceContext.getProductPackageKey());
            if (userMap == null) {
                userMap = new LinkedHashMap<>();
            }
            userMap.put(DeviceContext.getDeviceIdentify(), dto.getToken());
            redisCache.setCacheObject(userOld.getUserIdentify() + "_" + DeviceContext.getProductPackageKey(), userMap);

            redisCache.setCacheObject(dto.getToken(), DeviceContext.getDeviceIdentify() + "_" + DeviceContext.getProductPackageKey(), 60, TimeUnit.DAYS);
            productUserService.maybeSave(userOld);
            return ResponseObj.SUCCESS(dto);
        }catch (BusinessException e){
            log.error("登录失败:{}产品{}版本{}设备{}token{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), token);
            if (e.getCode() == 1001) {
                return ResponseObj.ERROR(e.getMessage(), "1001");
            }
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("通用登录失败:{}产品{}版本{}设备{}token{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), token);
            return ResponseObj.ERROR("登录失败");
        }

    }

    /**
     * 中国移动 验证本机号码
     * @param
     * @return
     */
    @Deprecated
    @GetMapping("/api/checkMobile")
    public ResponseObj<Map<String, String>> checkMobile(String phoneNumber, String token){
        try {
            Product product = productServiceImpl.getByPackageKey(DeviceContext.getProductPackageKey());
            Boolean isSelf = ChinaMobileUtils.checkMobile(phoneNumber, token, product.getCmAppId(), product.getCmAppKey(), product.getCmPublicKey());
            Map<String, String> map = new HashMap<>();
            map.put("phoneNumber", phoneNumber);
            if (isSelf) {
                map.put("isSelf", "0");
                User userOld = userServiceImpl.getByAccount(phoneNumber);
                if (userOld != null) {
                    map.put("isAccount", "0");
                } else {
                    map.put("isAccount", "1");
                }
            } else {
                map.put("isSelf", "1");
                map.put("isAccount", "1");
            }
            return ResponseObj.SUCCESS(map);
        }catch (BusinessException e){
            log.error("验证本机号码:{}产品{}版本{}设备{}token{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), token);
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            log.error("验证本机号码:{}产品{}版本{}设备{}token{}",e.getMessage(),DeviceContext.getProductPackageKey(), DeviceContext.getVersion(), DeviceContext.getDeviceIdentify(), token);
            return ResponseObj.ERROR("验证本机号码失败");
        }

    }


    /**
     * 退出登录
     * @param
     * @return
     */
    @GetMapping("/loginOut")
    public ResponseObj loginOut(){
        try {
            Product product = productServiceImpl.getByPackageKey(DeviceContext.getProductPackageKey());
            if (product != null && product.getLoginLimit() != null && product.getLoginLimit() > 0) {
                LinkedHashMap<String, String> userMap = redisCache.getCacheObject(DeviceContext.getUserIdentify() + "_" + DeviceContext.getProductPackageKey());
                if (userMap != null && userMap.size() > 0) {
                    if (userMap.containsKey(DeviceContext.getDeviceIdentify())) {
                        userMap.remove(DeviceContext.getDeviceIdentify());
                        redisCache.setCacheObject(DeviceContext.getUserIdentify() + "_" + DeviceContext.getProductPackageKey(), userMap);
                        try {
                            redisCache.deleteObject(userMap.get(DeviceContext.getDeviceIdentify()));
                        }catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            return ResponseObj.SUCCESS();
        }catch (BusinessException e){
            log.error("退出登录失败:{}",e.getMessage());
            return ResponseObj.ERROR(e.getMessage());
        }catch (Exception e){
            e.printStackTrace();
            log.error("退出登录失败:{}",e.getMessage());
            return ResponseObj.ERROR("退出登录失败。");
        }
    }



}
